package com.hxkj.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayFundTransOrderQueryRequest;
import com.alipay.api.request.AlipayFundTransToaccountTransferRequest;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayFundTransOrderQueryResponse;
import com.alipay.api.response.AlipayFundTransToaccountTransferResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.hxkj.client.service.BrokerOrderPayServiceClient;
import com.hxkj.client.service.LtsOrderClient;
import com.hxkj.config.AlipayConfig;
import com.hxkj.config.WAPAlipayConfig;
import com.hxkj.dao.CommonPaymentDao;
import com.hxkj.dao.CommonWithdrawDao;
import com.hxkj.domain.bo.PayParameter;
import com.hxkj.domain.bo.WithdrawParameter;
import com.hxkj.domain.enums.PaymentStatusEnum;
import com.hxkj.domain.po.CommonPayment;
import com.hxkj.domain.po.CommonWithdraw;
import com.hxkj.domain.po.InsuranceOrder;
import com.hxkj.lts.entity.Order;
import com.hxkj.service.AliPayService;
import com.hxkj.utils.DateUtil;
import com.hxkj.utils.UUIDUtil;
import com.platform.common.domain.exception.CustomMessageException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * 支付宝支付服务
 * <p>
 * Create by chenwei on 2018/7/9 14:30
 */
@Service("paymentService")
@Slf4j
public class AliPayServiceImpl implements AliPayService {

    @Resource
    private CommonPaymentDao commonPaymentDao;

    @Resource
    private BrokerOrderPayServiceClient brokerOrderPayServiceClient;

    @Resource
    private CommonWithdrawDao commonWithdrawDao;

    @Resource
    private LtsOrderClient ltsOrderClient;

    @Override
    public String alipay(PayParameter payParameter) throws Exception {
        Long now = System.currentTimeMillis();
        // 判断订单是否被创建
        List<CommonPayment> commonPayments = commonPaymentDao.get(CommonPayment.builder().orderId(payParameter.getId()).build());
        // 没有创建订单
        if (commonPayments.isEmpty()) {
            // 生成本地支付订单
            String id = UUIDUtil.generateUUID();
            CommonPayment commonPayment = CommonPayment.builder().id(id).amount(payParameter.getAmount())
                    // 业务订单号
                    .orderId(payParameter.getId())
                    // 商品名称
                    .product(payParameter.getName())
                    // 创建时间
                    .createTime(now)
                    // 更新时间
                    .updateTime(now)
                    // 订单状态
                    .status(PaymentStatusEnum.NON_PAYMENY.getType())
                    // 渠道
                    .payChannel(payParameter.getPayType())
                    .build();
            commonPaymentDao.save(commonPayment);
            // 构建支付宝支付请求
            JSONObject jsonObject = new JSONObject();
            // 支付订单 订单号
            jsonObject.put("out_trade_no", id);
            jsonObject.put("total_amount", payParameter.getAmount());
            jsonObject.put("subject", payParameter.getName());
//            // wap支付
//            jsonObject.put("product_code", "QUICK_WAP_PAY");
            jsonObject.put("product_code", "FAST_INSTANT_TRADE_PAY");
            jsonObject.put("return_url", payParameter.getReturnUrl());
            return generatePaymentOrder(jsonObject);
            // 已经创建了支付订单
        } else {
            // 判断订单状态,若支付,则返回已支付,若未支付,则继续支付
            CommonPayment commonPayment = commonPayments.get(0);
            // 若该订单未支付 继续支付
            if (StringUtils.equals(commonPayment.getStatus(), PaymentStatusEnum.NON_PAYMENY.getType())) {
                JSONObject jsonObject = new JSONObject();
                // 支付订单主键
                jsonObject.put("out_trade_no", commonPayment.getId());
                jsonObject.put("total_amount", payParameter.getAmount());
                jsonObject.put("subject", payParameter.getName());
                // wap支付
                jsonObject.put("product_code", "FAST_INSTANT_TRADE_PAY");
                jsonObject.put("return_url", payParameter.getReturnUrl());
                return generatePaymentOrder(jsonObject);
            } else {
                // 关闭或者已支付则不继续支付
                throw new CustomMessageException(400, "当前订单已经被支付");

            }
        }
    }

    @Override
    public void payCallback() throws Exception {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        HttpServletResponse httpResponse = attributes.getResponse();
        OutputStream out = httpResponse.getOutputStream();
        // 获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            log.info("支付宝回调信息为:{}", name + ":" + valueStr);
            // 乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
//            valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
            params.put(name, valueStr);
        }
        // 获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
        // 商户订单号
        String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
        // 支付宝交易号
        String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");
        // 交易状态
        String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");
        // 交易付款时间
        String gmt_payment = new String(request.getParameter("gmt_payment").getBytes("ISO-8859-1"), "UTF-8");
        // 交易创建时间
        String gmt_create = new String(request.getParameter("gmt_create").getBytes("ISO-8859-1"), "UTF-8");
        // 用户实际支付的金额
        String buyer_pay_amount = new String(request.getParameter("buyer_pay_amount").getBytes("ISO-8859-1"), "UTF-8");
        // 商家实际收到的金额
        String receipt_amount = new String(request.getParameter("receipt_amount").getBytes("ISO-8859-1"), "UTF-8");
        // 总金额
        String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"), "UTF-8");

        // 获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
        // 计算得出通知验证结果
        //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
        log.info("支付宝公钥:{}", WAPAlipayConfig.ALIPAY_PUBLIC_KEY);
        log.info("编码为:{}", WAPAlipayConfig.CHARSET);
        boolean verify_result = AlipaySignature.rsaCheckV1(params, WAPAlipayConfig.ALIPAY_PUBLIC_KEY, WAPAlipayConfig.CHARSET, WAPAlipayConfig.SIGNTYPE);

        if (verify_result) {// 验证成功
            // 交易结束
            if (trade_status.equals("TRADE_FINISHED")) {
                List<CommonPayment> commonPayments = commonPaymentDao.get(CommonPayment.builder().id(out_trade_no).build());
                if (!commonPayments.isEmpty()) {
                    CommonPayment commonPayment = commonPayments.get(0);
                    // 若该订单已经被处理
                    if (!commonPayment.getStatus().equals(PaymentStatusEnum.NON_PAYMENY.getType())) {
                        // 通知支付宝
                        log.info("订单:{}已经被处理,将要通知支付宝", out_trade_no);
                        out.write("success".getBytes());
                        return;
                    }
                    commonPayment.setUpdateTime(System.currentTimeMillis());
                    commonPayment.setTradeStatus(trade_status);
                    commonPayment.setPayId(trade_no);
                    commonPayment.setGmtPayment(DateUtil.formatDate(gmt_payment));
                    commonPayment.setGmtCreate(DateUtil.formatDate(gmt_create));
                    commonPayment.setBuyerPayAmount(new BigDecimal(buyer_pay_amount));
                    commonPayment.setReceiptAmount(new BigDecimal(receipt_amount));
                    commonPayment.setStatus(PaymentStatusEnum.PAIED.getType());
                    commonPaymentDao.update(commonPayment);

                    // ------ 通知业务调用方
                    InsuranceOrder insuranceOrder = new InsuranceOrder();
                    insuranceOrder.setOrderId(commonPayment.getOrderId());
                    insuranceOrder.setOrderAmount(new BigDecimal(total_amount));
                    // 支付成功
                    insuranceOrder.setOrderStatus("15");
                    brokerOrderPayServiceClient.callback(insuranceOrder);
                    // 通知业务方
                    out.write("success".getBytes());
                } else {
                    log.error("异步回调找不到订单:,订单号为:{}", trade_no);
                    out.write("fail".getBytes());
                }
            } else if (trade_status.equals("TRADE_SUCCESS")) {
                List<CommonPayment> commonPayments = commonPaymentDao.get(CommonPayment.builder().id(out_trade_no).build());
                if (!commonPayments.isEmpty()) {
                    CommonPayment commonPayment = commonPayments.get(0);
                    // 判断该笔订单的状态是否是未支付
                    if (!commonPayment.getStatus().equals(PaymentStatusEnum.NON_PAYMENY.getType())) {
                        log.info("订单:{}已经被处理,将要通知支付宝", out_trade_no);
                        // 通知支付宝
                        out.write("success".getBytes());
                        return;
                    }
                    commonPayment.setUpdateTime(System.currentTimeMillis());
                    commonPayment.setTradeStatus(trade_status);
                    commonPayment.setPayId(trade_no);
                    commonPayment.setGmtPayment(DateUtil.formatDate(gmt_payment));
                    commonPayment.setGmtCreate(DateUtil.formatDate(gmt_create));
                    commonPayment.setBuyerPayAmount(new BigDecimal(buyer_pay_amount));
                    commonPayment.setReceiptAmount(new BigDecimal(receipt_amount));
                    commonPayment.setStatus(PaymentStatusEnum.PAIED.getType());
                    commonPaymentDao.update(commonPayment);


                    // 通知业务方
//                    // ------ 通知业务调用方
//                    InsuranceOrder insuranceOrder = new InsuranceOrder();
//                    insuranceOrder.setOrderId(commonPayment.getOrderId());
//                    insuranceOrder.setOrderAmount(new BigDecimal(total_amount));
//                    // 支付成功
//                    insuranceOrder.setOrderStatus("15");
//
//                    ResultMessageStruct resultMessageStruct = brokerOrderPayServiceClient.callback(insuranceOrder);
//                    if (resultMessageStruct.getCode() == 200) {
//                        log.info("业务方信息为:{}", resultMessageStruct.getMessage());
//                        // 通知支付宝
//                        out.write("success".getBytes());
//                    } else {
//                        log.info("通知业务方失败:{}", resultMessageStruct.getMessage());
//                        out.write("fail".getBytes());
//                }
                    Order order = Order.builder()
                            .orderId(commonPayment.getOrderId())
                            .payAmount(new BigDecimal(total_amount))
                            .build();
                    ltsOrderClient.payCallback(order);
                    log.debug("通知业务方完成");
                }
            }
        } else {
            log.error("异步回调签名验证失败:,订单号为:{}", trade_no);
            // 失败
            out.write("fail".getBytes());
        }
    }


    /**
     * 生成支付宝订单
     *
     * @param jsonObject
     * @throws Exception
     */
    private String generatePaymentOrder(JSONObject jsonObject) throws Exception {
        //获得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key,
                "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);

        //设置请求参数
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
        alipayRequest.setReturnUrl((String) jsonObject.get("return_url"));
        // 创建API对应的request
//        AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
        // 在公共参数中设置回跳和通知地址
//        alipayRequest.setNotifyUrl(WAPAlipayConfig.notify_url);
        // 业务参数
        alipayRequest.setBizContent(jsonObject.toJSONString());
        String form = "";
        try {
            // 调用SDK生成表单
            form = alipayClient.pageExecute(alipayRequest).getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new CustomMessageException(400, e.getMessage());

        }
        return form;
    }

    /**
     * 处理支付成功
     *
     * @param jsonObject
     * @throws Exception
     */
    private String handCallbackEvent(JSONObject jsonObject) throws Exception {
        return "";
    }


    /**
     * 获取支付状态
     *
     * @param payParameter
     * @throws Exception
     */
    @Override
    public void getPayStatus(PayParameter payParameter) throws Exception {
        //获得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key,
                "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);

        // 获取支付订单
        List<CommonPayment> commonPayments = commonPaymentDao.get(CommonPayment.builder().orderId(payParameter.getId()).build());
        if (commonPayments.isEmpty()) {
            throw new CustomMessageException(400, "业务订单:" + payParameter.getId() + "不存在");
        }
        CommonPayment commonPayment = commonPayments.get(0);
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();

        // 构建请求参数
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("out_trade_no", commonPayment.getId());
        // 支付宝订单号
        jsonObject.put("trade_no", commonPayment.getPayId());
        request.setBizContent(jsonObject.toJSONString());

        // 支付宝的业务通知中，只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时，支付宝才会认定为买家付款成功。
        AlipayTradeQueryResponse response = alipayClient.execute(request);
        if (response.isSuccess()) {
            String tradeStatus = response.getTradeStatus();
            log.info("支付查询调用成功,当前订单的支付状态为:{}", response.getTradeStatus());
            switch (tradeStatus) {
                case "WAIT_BUYER_PAY":
                    throw new CustomMessageException(100, "当前订单未支付");
                case "TRADE_CLOSED":
                    throw new CustomMessageException(101, "当前已经被支付宝关闭");
                case "TRADE_SUCCESS":
                    log.info("订单:{}支付成功", commonPayment.getOrderId());
                    return;
                case "TRADE_FINISHED":
                    log.info("订单:{}支付成功", commonPayment.getOrderId());
                    return;
                default:
                    throw new CustomMessageException(102, "未知的支付结果");
            }
        } else {
            // 20000 支付宝服务不可用
            if (StringUtils.equals(response.getCode(), "20000")) {
                log.error("当前支付宝服务不可用,支付宝返回结果为:{}", JSONObject.toJSON(response));
                throw new CustomMessageException(20000, "支付宝系统繁忙");
            } else {
                // 否则为交易不存在
                log.error("调用支付宝查询支付结果接口失败,支付宝返回结果:{}", JSONObject.toJSON(response));
                throw new CustomMessageException(103, "交易不存在");
            }
        }
    }

    @Override
    public void withdraw(WithdrawParameter withdrawParameter) throws Exception {
        if (withdrawParameter.getAmount().compareTo(new BigDecimal("0.1")) == -1) {
            log.warn("最低提现金额为0.1元");
            throw new CustomMessageException("最低提现金额为0.1元");
        }
        Long now = System.currentTimeMillis();
        CommonWithdraw query = CommonWithdraw.builder()
                .orderId(withdrawParameter.getOrderId())
                .status("0")
                .build();
        List<CommonWithdraw> commonWithdraws = commonWithdrawDao.get(query);
        if (commonWithdraws.size() > 0) {
            // 401为订单已经转账成功,调用方拿到此状态以后直接修改业务订单状态为成功
            throw new CustomMessageException(401, "该订单已经提现成功");
        }
        // 支付订单id
        String id = UUIDUtil.generateUUID();
        CommonWithdraw commonWithdraw = CommonWithdraw.builder()
                .id(id)
                .orderId(withdrawParameter.getOrderId())
                .createTime(now)
                .updateTime(now)
                .accountName(withdrawParameter.getAccountName())
                // 私有账户
                .accountType("PRIVATE")
                .amount(withdrawParameter.getAmount())
                .accountNo(withdrawParameter.getAccountNo())
                .channel("alipay")
                // 2为处理中
                .status("2")
                .build();
        commonWithdrawDao.save(commonWithdraw);

        //获得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key,
                "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);
        AlipayFundTransToaccountTransferRequest request = new AlipayFundTransToaccountTransferRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_biz_no", id);
        bizContent.put("payee_type", "ALIPAY_LOGONID");
        bizContent.put("payee_account", withdrawParameter.getAccountNo());
        bizContent.put("amount", withdrawParameter.getAmount().toString());
        // 业务名称 如: 红包 退款 打赏奖励
        bizContent.put("payer_show_name", withdrawParameter.getBusinessName());
        bizContent.put("payee_real_name", withdrawParameter.getAccountName());
        bizContent.put("remark", withdrawParameter.getBusinessName());
        request.setBizContent(bizContent.toJSONString());
        AlipayFundTransToaccountTransferResponse response = alipayClient.execute(request);
        if (response.isSuccess()) {
            String code = response.getCode();
            String subCode = response.getSubCode();

            // 若服务器返回错误,需要二次查询结果
            if ("20000".equals(code) || "40004".equals(code) || "SYSTEM_ERROR".equals(subCode)) {
                AlipayFundTransOrderQueryRequest fundTransOrderQueryRequest = new AlipayFundTransOrderQueryRequest();
                JSONObject jsonObject = JSONObject.parseObject(response.getBody());
                JSONObject transferResponse = jsonObject.getJSONObject("alipay_fund_trans_toaccount_transfer_response");
                JSONObject jsonBizContent = new JSONObject();
                jsonBizContent.put("out_biz_no", transferResponse.getString("out_biz_no"));
                jsonBizContent.put("order_id", transferResponse.getString("order_id"));
                request.setBizContent(jsonBizContent.toJSONString());
                AlipayFundTransOrderQueryResponse response1 = alipayClient.execute(fundTransOrderQueryRequest);
                // 若调用失败
                if (!response.isSuccess()) {
                    log.warn("用户:【{}】发起提现失败,支付宝账户为:【{}】,详细信息:{}",
                            withdrawParameter.getAccountName(), withdrawParameter.getAccountNo(), response.getBody());
                    // 提现失败
                    commonWithdraw.setStatus("1");
                    commonWithdraw.setResultDetail(response.getSubMsg());
                    commonWithdrawDao.update(commonWithdraw);

                    throw new CustomMessageException(response.getSubMsg());
                }

                if (response.isSuccess()) {
                    // 提现成功
                    log.info("用户:【{}】发起提现成功,支付宝账户为:【{}】,详细信息:{}",
                            withdrawParameter.getAccountName(), withdrawParameter.getAccountNo(), response.getBody());
                    commonWithdraw.setStatus("0");
                    commonWithdraw.setResultDetail(response.getSubMsg());
                    commonWithdrawDao.update(commonWithdraw);
                }
            } else {
                // 提现成功
                log.info("用户:【{}】发起提现成功,支付宝账户为:【{}】,详细信息:{}",
                        withdrawParameter.getAccountName(), withdrawParameter.getAccountNo(), response.getBody());
                commonWithdraw.setStatus("0");
                commonWithdraw.setResultDetail(response.getMsg());
                commonWithdrawDao.update(commonWithdraw);
            }
        }

        if (!response.isSuccess()) {
            log.warn("用户:【{}】发起提现失败,支付宝账户为:【{}】,详细信息:{}",
                    withdrawParameter.getAccountName(), withdrawParameter.getAccountNo(), response.getBody());
            // 提现失败
            commonWithdraw.setStatus("1");
            commonWithdraw.setResultDetail(response.getSubMsg());
            commonWithdrawDao.update(commonWithdraw);

            throw new CustomMessageException(response.getSubMsg());
        }
    }
}